//
//  HtmlCollector.m
//  MarketDataColloctor
//
//  Created by jiro on 10/03/04.
//  Copyright 2010 jiro music. All rights reserved.
//

#import "WebResourceCollector.h"

enum ErrorType 
{
	Error_UTF8Encoding,
	
	Error_SaveFile,
	
};

@interface ErrorInfo : NSObject
{
	ErrorType type;
	NSString* url;
	NSString* savePath;
	NSString* message;	
}
@property ( assign ) ErrorType type;
@property ( assign ) NSString* url;
@property ( assign ) NSString* savePath;
@property ( assign ) NSString* message;	

@end

@implementation ErrorInfo

@synthesize type;
@synthesize url;
@synthesize savePath;
@synthesize message;	

@end

@interface ThreadArg : NSObject
{
	NSMutableArray* urls;
	
	NSMutableArray* htmlStrings;
}

- (id) init;

@property( assign ) NSMutableArray* urls;

@property( assign ) NSMutableArray* htmlStrings;

@end

@implementation ThreadArg

@synthesize urls;

@synthesize htmlStrings;

- (id) init
{
	self = [ super init ];

	urls = [ NSMutableArray array ];
	htmlStrings = [ NSMutableArray array ];

	return self;
}

@end

const int THREAD_COUNT = 6;

@implementation WebResourceCollector

- (id) init
{
	self = [ super init ];
	self = [ self initWithEncoding: NSUTF8StringEncoding ];
	return self;
}

- (id) initWithEncoding: (NSStringEncoding) encoding
{
	self = [ super init ];
	yahooEnigmaOption = NO;
	htmlEncoding = encoding;
	threadCount = THREAD_COUNT;
	return self;
}

- (id) initWithYahooEnigmaOption: (BOOL) enable htmlEncoding: (NSStringEncoding) encoding
{
	self = [ super init ];
	yahooEnigmaOption = enable;
	htmlEncoding = encoding;
	threadCount = THREAD_COUNT;
	return self;
}

- (void) collectContentsOfThreadFunc: (id) threadArg
{
	ThreadArg* arg = (ThreadArg*) threadArg;
	if ( [ arg.urls count ] == 0 )
	{
		return;
	} 

	NSEnumerator* e = [ arg.urls objectEnumerator ];
	NSURL* url;
	while ( url = [ e nextObject ] )
	{
//		NSLog( @"%x, %@", self, url );
		NSData* data = [ NSData dataWithContentsOfURL: url ];
		if ( [ data length ] == 0 )
		{
			continue;
		}

		if ( NO )
//		if ( yahooEnigmaOption )
		{	//	18,19 バイト目をエンコードできないので削除する
			const int bufferSize = 4096 * 10;
			char bytes[ bufferSize ] = { 0 };
			const int length = [ data length ] - 2;
			if ( length <= 0 )
			{
				continue;
			}
			[ data getBytes: bytes range:NSMakeRange( 0, 17 ) ];
			[ data getBytes: bytes + 18 range: NSMakeRange( 20, [ data length ] - 20 ) ];
			data = [ NSData dataWithBytes: bytes length: length ];
		}

		NSString* contents = [ [ NSString alloc ] initWithData: data encoding: htmlEncoding ];
		if ( contents == nil )
		{
			ErrorInfo* info = [ [ ErrorInfo alloc ] init ];
			info.type = Error_UTF8Encoding;
			info.url = [ url description ];
			[ errorInfos addObject: arg ];
			continue;
		}

		[ arg.htmlStrings addObject: contents ];
	}

	[ [ NSGarbageCollector defaultCollector ] collectIfNeeded ];
}

- (NSString*) collectContentsOf: (NSURL*) url
{
	id urls = [ NSArray arrayWithObject: url ];
	id htmls = [ NSMutableArray array ];
	[ self collectContentsOf: urls intoStrings: htmls ];
	return [ htmls objectAtIndex: 0 ];
}


- (void) collectContentsOf: (NSArray*) urls intoStrings: (NSMutableArray*) htmlStrings
{
	// create thread argument
	NSMutableArray* threadArgs = [ NSMutableArray array ];
	for ( int i = 0; i < threadCount; i++ )
	{
		ThreadArg* arg = [ [ ThreadArg alloc ] init ];
		[ threadArgs addObject: arg ];
 	}

	//	divide jobs
	int index = 0;
	NSEnumerator* e = [ urls objectEnumerator ];
	NSURL* url;
	while ( url = [ e nextObject ] )
	{
		ThreadArg* arg = [ threadArgs objectAtIndex: index ];
		[ arg.urls addObject: url ];

		index++;
		index %= threadCount;
		
	}

	// start thread
	NSMutableArray* threads = [ [ NSMutableArray alloc ] init ];
	for ( int i = 0; i < threadCount; i++ )
	{
		NSThread* thread =
			[ [ NSThread alloc ] 
				initWithTarget: self 
				selector: @selector( collectContentsOfThreadFunc: )
				object: [ threadArgs objectAtIndex: i ] ];
		[ threads addObject: thread ];
		[ thread start ];
	}

	//	wait for complete job
	for ( int i = 0; i < threadCount; i++ )
	{
		NSThread* thread = [ threads objectAtIndex: i ];
		while ( [ thread isExecuting ] || NO == [ thread isFinished ] )
		{
			[ NSThread sleepForTimeInterval: 0.5 ];
		}
	}
	
	//	collect htmls
	for ( int i = 0; i < threadCount; i++ ) 
	{
		ThreadArg* arg = [ threadArgs objectAtIndex: i ];
		NSEnumerator* e = [ arg.htmlStrings objectEnumerator ];
		NSString* s;
		while ( s =  [ e nextObject ] )
		{
			[ htmlStrings addObject: s ];
		}
	}
}

- (NSString*) errorMessage
{
	if ( [ errorInfos count ] == 0 )
	{
		return nil;
	}

	NSMutableString* encodingError = [ [ NSMutableString alloc ] initWithString: @"エンコーディングに失敗\n" ];
	NSMutableString* saveFileError = [ [ NSMutableString alloc ] initWithString: @"ファイル保存に失敗\n" ];
	NSEnumerator* e = [ errorInfos objectEnumerator ];
	ErrorInfo* info;
	while ( info = [ e nextObject ] )
	{
		switch ( info.type )
		{
		case Error_UTF8Encoding:
			[ encodingError appendFormat: @"\t%@save path: %@\n\turl: %@\n", info.savePath, info.url ];
			break;
		case Error_SaveFile:
			[ encodingError appendFormat: @"\t%@save path: %@\n\turl: %@\n\t%@\n", info.savePath, info.url, info.message ];
			break;
		}
	}
	return [ NSString stringWithFormat: @"%@\n%@", encodingError, saveFileError ];
}

-(NSString*) outputUrls: (NSArray*) codes andMarketDataType: (int) marketDataType
{
	return nil;
}

@end
